#ifndef _REGULAR_GRID_HOST_H
#define _REGULAR_GRID_HOST_H

#include "..\cuCommon\cuTypes.h"
#include "..\cuCommon\cuMath.h"

#include "Ray.h"

template <class T>
struct TRegularGrid_Host
{
  T * m_pData;
  uint32 m_Sx, m_Sy, m_Sz;

  uint32 m_Total;

  T operator () (uint32 index) const
  {
    return this->m_pData[index];
  }

  T & operator () (uint32 index) 
  {
    return this->m_pData[index];
  }

  T operator () (uint32 i, uint32 j, uint32 k) const
  {
    return this->m_pData[i + m_Sx * (j + m_Sy * k)];
  }

  T & operator () (uint32 i, uint32 j, uint32 k) 
  {
    return this->m_pData[i + m_Sx * (j + m_Sy * k)];
  }
};

typedef TRegularGrid_Host<float>    SDistanceField_host;
//typedef TRegularGrid_Host<SRay>     SRayBuffer;
//typedef TRegularGrid_Host<uchar4>   SColorBuffer;
//typedef TRegularGrid_Host<float>    SDepthBuffer;
//typedef TRegularGrid_Host<uint32>   SStencilBuffer;
//typedef TRegularGrid_Host<uint32>   SIndexBuffer;
typedef TRegularGrid_Host<float>    SFloatGrid_host;

template <class T>
static TRegularGrid_Host<T> * RegularGrid_Host(TRegularGrid_Host<T> *pGrid, uint32 sx, uint32 sy, uint32 sz, bool bClear = false)
{
  if (pGrid != NULL)
  {
    pGrid->m_Sx = sx;
    pGrid->m_Sy = sy;
    pGrid->m_Sz = sz;

    pGrid->m_Total = sx * sy * sz;

    pGrid->m_pData = new T[pGrid->m_Total];

    if (bClear)
      memset(pGrid->m_pData, 0, pGrid->m_Total * sizeof(T));

    return pGrid;
  }
  else
  {
    return NULL;
  }
}

template <class T>
static TRegularGrid_Host<T> * RegularGrid_Host(TRegularGrid_Host<T> *pGrid, uint32 sx, uint32 sy, uint32 sz, T elem)
{
  if (pGrid != NULL)
  {
    pGrid->m_Sx = sx;
    pGrid->m_Sy = sy;
    pGrid->m_Sz = sz;

    pGrid->m_Total = sx * sy * sz;

    pGrid->m_pData = new T[pGrid->m_Total];

    for (uint32 idx = 0; idx < pGrid->m_Total; idx++)
      pGrid->m_pData[idx] = elem;
  }

  return pGrid;
}

template <class T>
static TRegularGrid_Host<T> * RegularGrid_Host(TRegularGrid_Host<T> *pGrid)
{
  if (pGrid != NULL)
  {
    pGrid->m_Sx = 0;
    pGrid->m_Sy = 0;
    pGrid->m_Sz = 0;

    pGrid->m_Total = 0;

    pGrid->m_pData = NULL; 
  }

  return pGrid;
}

template <class T>
static TRegularGrid_Host<T> * Release(TRegularGrid_Host<T> *pGrid)
{
  if (pGrid != NULL)
  {
    pGrid->m_Sx = 0;
    pGrid->m_Sy = 0;
    pGrid->m_Sz = 0;

    pGrid->m_Total = 0;

    delete [] pGrid->m_pData;

    pGrid->m_pData = NULL;
  }

  return pGrid;
}

template <class T>
SDH_CALL T Get(TRegularGrid_Host<T> *pGrid, uint32 ix, uint32 iy, uint32 iz)
{

#ifdef _DEBUG  // do additional checks in Debug
  if (pGrid != NULL && pGrid->m_pData != NULL)
  {
    ix = clamp(ix, (uint32) 0, uint32 (pGrid->m_Sx - 1));
    iy = clamp(iy, (uint32) 0, uint32 (pGrid->m_Sy - 1));
    iz = clamp(iz, (uint32) 0, uint32 (pGrid->m_Sz - 1));
  }
#endif

  return pGrid->m_pData[ix + pGrid->m_Sx * (iy + pGrid->m_Sy * iz)];
}

template <class T>
SDH_CALL T Set(TRegularGrid_Host<T> *pGrid, T t, uint32 ix, uint32 iy, uint32 iz)
{

#ifdef _DEBUG // do additional checks in Debug
  if (pGrid != NULL && pGrid->m_pData != NULL)
  {
    ix = clamp(ix, (uint32) 0, uint32 (pGrid->m_Sx - 1));
    iy = clamp(iy, (uint32) 0, uint32 (pGrid->m_Sy - 1));
    iz = clamp(iz, (uint32) 0, uint32 (pGrid->m_Sz - 1));
  }
#endif

  pGrid->m_pData[ix + pGrid->m_Sx * (iy + pGrid->m_Sy * iz)] = t;

  return t;
}
template <class T>
SDH_CALL void Swap (TRegularGrid_Host<T> * pGrid1, TRegularGrid_Host<T> * pGrid2)
{
  T * temp;
  temp = pGrid1->m_pData;
  pGrid1->m_pData = pGrid2->m_pData;
  pGrid2->m_pData = temp;
}

template <class T>
SDH_CALL void Clear (TRegularGrid_Host<T> * pGrid)
{
  memset(pGrid->m_pData, 0, pGrid->m_Total * sizeof(T));
}

template <class T>
SDH_CALL int3 Dim (TRegularGrid_Host<T> * pGrid)
{
  return i3(pGrid->m_Sx, pGrid->m_Sy, pGrid->m_Sz);
}

#endif